import binascii
import datetime
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.core.urlresolvers import reverse
from django.http.response import HttpResponseRedirect, HttpResponse,\
    HttpResponseNotFound
from django.shortcuts import render
from django.utils.timezone import utc
import logging
import os
from mappapp.models import QueryForm, uuid_length, Query
from mappapp.settings import MAPP_SEQ_FILE, MAPP_FILE, MAPP_BLAST_FILE, \
                            MAPP_STAT_FILE, MAPP_MSA_FILE, MAPP_TREE_FILE
from tasks import run_mapp
from mappapp.tasks import get_results, write_csv_results, create_settings
from argparse import ArgumentError

log = logging.getLogger('mappapp')



class DownType(object):
    
    result = 'result'
    seq = 'seq'
    seqs = 'seqs'
    stats = 'stats'
    msa = 'msa'
    tree = 'tree'
    mapp = 'mapp'
        
    def __init__(self, uuid):
        self.files = {DownType.seq: MAPP_SEQ_FILE.format(id=uuid),  # @UndefinedVariable
             DownType.seqs: MAPP_BLAST_FILE.format(id=uuid),  # @UndefinedVariable
             DownType.stats: MAPP_STAT_FILE.format(id=uuid),  # @UndefinedVariable
             DownType.msa: MAPP_MSA_FILE.format(id=uuid),   # @UndefinedVariable
             DownType.tree: MAPP_TREE_FILE.format(id=uuid),  # @UndefinedVariable
             DownType.mapp: MAPP_FILE.format(id=uuid)}  # @UndefinedVariable
    
    

def index(request):
    if request.method == 'POST':
        form = QueryForm(request.POST)
        if form.is_valid():
            query = form.save(commit=False)
            query.uuid = binascii.hexlify(os.urandom(uuid_length/2))
            query.date = datetime.datetime.utcnow().replace(tzinfo=utc)
            query.save()
            #run mapp application as task
            mapp_settings = create_settings(query.uuid,
                                            clusters=query.clusters,
                                            msa=query.msa,
                                            tree=query.tree)            
            run_mapp.delay(query.uuid, query.sequence, # @UndefinedVariable
                           query.mutations, mapp_settings)  
            return HttpResponseRedirect(reverse('mapp:detail', args=(query.uuid,)))
    else:
        form = QueryForm() #unbound form
        
    
    return render(request, 'mapp/index.html', {
            'form': form,
    })

def detail(request, query_id):
    context = {}
    context['query_id'] = query_id
        
    context.update(get_state_and_query(query_id))    
    
    return render(request, 'mapp/detail.html', context)

            
def result(request, query_id):
    context = {}
    context['query_id'] = query_id
    context.update(get_state_and_query(query_id))
    if context['state'] != 'completed':
        return HttpResponseRedirect(reverse('mapp:detail', args=(query_id,)))
    
    results = get_results(context['query'].uuid, context['query'].mutations)
    
    page = request.GET.get('page')
    paginator = Paginator(results, 25)  
    try:  
        context['results'] = paginator.page(page)
    except PageNotAnInteger:
        context['results'] = paginator.page(1)
    except EmptyPage:
        context['results'] = paginator.page(paginator.num_pages)
        
    return render(request, 'mapp/result.html', context)


def download(request, query_id, dwltype):
    context = get_state_and_query(query_id)
    if context['state'] != 'completed':
        return HttpResponseRedirect(reverse('mapp:detail', args=(query_id,)))

    dt = DownType(query_id)
    response = HttpResponse(content_type='text/csv')
    if dwltype == DownType.result:
        response['Content-Disposition'] = 'attachment; filename="%s.csv"' % query_id
        try:
            response = write_csv_results(context['query'].uuid,
                                     context['query'].mutations,
                                     response)
        except IOError:
            return HttpResponseNotFound('Result or msa file not found for id: %s' % query_id) 
    else:
        response['Content-Disposition'] = 'attachment; filename="%s.%s"' % (query_id, dwltype)
        try:
            with open(dt.files[dwltype], 'r') as f:
                for line in f:
                    response.write(line)
        except KeyError:
            return HttpResponseNotFound('Download type has wrong value: %s.' % dwltype)
        except IOError:
            return HttpResponseNotFound('File not found: %s.' % dt.files[dwltype])
        
    return response



def is_non_zero_file(fpath):  
    return True if os.path.isfile(fpath) and os.path.getsize(fpath) > 0 else False


def get_state_and_query(query_id):
    '''
    Check database and file for determining the sate of query_id analysis
    :returns: dictionary { 'state' = 'not exists' OR 'completed' OR 'pending' OR 'no files',
                           'query' = query (if exists in database) }
    '''
    seqpath = MAPP_SEQ_FILE.format(id=query_id)
    mapppath = MAPP_FILE.format(id=query_id)
    context = dict()
    try:
        query = Query.objects.get(uuid=query_id)
    except Query.DoesNotExist:
        context['state'] = 'not exists'
    else:
        context['query'] = query
        if is_non_zero_file(seqpath):
            if is_non_zero_file(mapppath):
                context['state'] = 'completed'
            else:
                context['state'] = 'pending'
        else:
            context['state'] = 'no files'
    return context
